﻿#pragma once

#ifndef DATA_HPP
#define DATA_HPP

#include <cstdint>
#include <map>
#include <utility>
#include <vector>
#include <string>
#include <string_view>
#include <print>

#include "zzj.col.hpp"

namespace maze
{
	using namespace std::literals;
	using namespace col;

	enum class Attr : std::int_fast8_t
	{
		ROAD = 0,	// 路
		WALL,		// 墙
		TRAP,		// 陷阱
		TREASURE	// 宝藏
	};

	using Object =
	struct Obj
	{
		Attr attr{ Attr::WALL };
		std::int32_t val{};
	};

	// 坐标
	using Locate = std::pair<std::int32_t, std::int32_t>;
	// 路径
	using Path = std::vector<Locate>;

	struct Map
	{
		std::size_t m_width{};
		std::size_t m_height{};
		std::vector<std::vector<Obj>> m_map;

		Map(std::size_t const width, std::size_t const height)
			: m_width{ width }, m_height{ height }
		{
			m_map.resize((m_height * m_width),
				std::vector<Obj>(m_height, Obj()));
		}

		bool inpFrmFile(std::string_view file_name = "map_inp.ini");
		bool out2File(std::string_view file_name = "map_out.ini");

		std::pair<Path, std::int32_t> calcPath(std::size_t start, std::size_t end) const;

		[[nodiscard]] bool display() const;
		[[nodiscard]] bool displayPath(Path& path) const;
		[[nodiscard]] bool displayPathGraph(Path& path) const;
	};

	inline bool Map::display() const {

		if (m_map.empty()) {
			return false;
		}

		constexpr int wide{ 3 };
	    // 打印列号
	    auto col = Color(CName::CYAN);
	    std::print(R"(L\C )");
	    for (auto i = 0u; i < m_width; ++i) {
			std::print("{: <{}} ", i + 1, wide);
	    }
	    std::print("\n");

	    // 打印矩阵和行号
	    for (std::size_t i = 0; i < m_height; ++i) {
	        // 打印行号
	        auto row_col = Color(CName::GREEN);
			std::print("{: <{}} ", i + 1, wide);

	        for (std::size_t j = 0; j < m_width; ++j) {
	            auto ele_col = Color(CName::WHITE);
	            switch (m_map[i][j].attr) {
	                case Attr::ROAD:
	                    col.setPrn(CName::WHITE);
	                    std::print("{: <{}} ", "路", wide);
	                    break;
	                case Attr::WALL:
	                    col.setPrn(CName::YELLOW);
	                    std::print("{: <{}} ", "墙", wide);
	                    break;
	                case Attr::TRAP:
	                    col.setPrn(CName::RED);
	                    std::print("{: <{}} ", "陷", wide);
	                    break;
	                case Attr::TREASURE:
	                    col.setPrn(CName::BLUE);
	                    std::print("{: <{}} ", "宝", wide);
	                    break;
	                default:
	                    std::print("{: <{}} ", "？", wide);
	            }
	        }
			std::print("\n");
	    }

	    return true;
	}

	inline void init_map(Map& map, std::size_t const rows, std::size_t const cols)
	{
	    // 创建一个指定大小的二维向量
	    map.m_map.resize(rows, std::vector<Obj>(cols));

	    // 设置地图上的某些位置为不同属性的格子
	    for (std::size_t i = 0; i < rows; ++i) {
	        for (std::size_t j = 0; j < cols; ++j) {
	            // 默认为墙壁
	            map.m_map[i][j].attr = Attr::WALL;
	            map.m_map[i][j].val = 0;

	            // 设置某些特定位置为道路、陷阱或宝藏
	            if (i % 2 == 0 && j % 2 == 0) {
	                map.m_map[i][j].attr = Attr::ROAD;
	                map.m_map[i][j].val = 0;
	            } else if (i == 1 && j == 1) {
	                map.m_map[i][j].attr = Attr::TREASURE;
	                map.m_map[i][j].val = 100;
	            } else if (i == 3 && j == 3) {
	                map.m_map[i][j].attr = Attr::TRAP;
	                map.m_map[i][j].val = -10;
	            }
	        }
	    }
	}

	[[nodiscard]] inline auto projection_conversion(std::size_t const l_len, std::size_t const c_len, 
		std::size_t const g_len, bool const is_len = true)
		-> std::pair<std::size_t, std::size_t>
	{
		std::size_t divisor{};
		if (is_len) {
			divisor = l_len;
		} else {
			divisor = c_len;
		}

		auto x = g_len / divisor;
		auto y = g_len % divisor;

		return { x, y };
	}

	/**
	 * @brief 类，表示一个带权邻接矩阵图。
	 */
	using WeightedAdjMatrixGraphMap =
	struct GMap : public Map
	{
		std::size_t m_vertexCnt{};	///> 顶点数量
		std::size_t m_edgeCnt;		///> 边数量
		std::vector<std::vector<std::int32_t>> m_adjMatrix; ///> 邻接矩阵

		/**
		 * @brief 构造一个新的 WGraph（WeightedAdjMatrixGraph） 对象。
		 * @param map 图中的顶点数。
		 */
		explicit GMap(Map const& map)
			: Map{ map }, m_vertexCnt{ map.m_width * map.m_height}, m_edgeCnt{0}
		{
			m_adjMatrix.resize(m_vertexCnt,
				std::vector<std::int32_t>(m_vertexCnt, 0));
		}

		void addEdge(std::size_t const src, std::size_t const dest, std::int32_t const val)
		{
			m_adjMatrix[src][dest] = val;
			m_adjMatrix[dest][src] = val;
		}

		void advProc();

		[[nodiscard]] auto dijkstra(int const start, int const end) const
			-> std::pair<std::vector<int>, int>;

		void printPath(const std::vector<int>& path) const;
		void printPath2(const std::vector<int>& path) const;

		void printGraph() const {
			std::println("带权重的图的邻接矩阵表示：");
			// 打印列号
			{
			    auto col = Color(CName::CYAN);
			    std::print(R"(L\C  )");
			    for (int j = 0; j < m_vertexCnt; ++j) {
			        std::print("{: <5} ", j);
			    }
			}
			std::print("\n");
			// 打印矩阵
			for (auto i = 0; i < m_vertexCnt; ++i) {
			    // 打印行号
			    {
			        auto col = Color(CName::GREEN);
			        std::print("{: <4} ", i);
			    }
			    for (int j = 0; j < m_vertexCnt; ++j) {
			        if (m_adjMatrix[i][j] == 0) {
			            std::print("{: <5} ", "∞");
			        } else {
			            std::print("{: <5} ", m_adjMatrix[i][j]);
			        }
			    }
			    std::print("\n");
			}
		}


	};
}

#endif